package com.xbongbong.pay.platform.wechatpay.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.xbongbong.paas.toolbox.util.MD5Util;
import com.xbongbong.pay.enums.PayErrorEnum;
import com.xbongbong.pay.exception.PayApiException;
import com.xbongbong.pay.platform.wechatpay.client.WeChatClient;
import com.xbongbong.pay.platform.wechatpay.config.WeChatPayConfig;
import com.xbongbong.pay.platform.wechatpay.config.WeChatPayMeta;
import com.xbongbong.pay.platform.wechatpay.config.WeChatPayMetaContainer;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatApplyRefundErrorEnum;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatPayErrorEnum;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatQueryRefundErrorEnum;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatServerEnum;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatV3UrlEnum;
import com.xbongbong.pay.platform.wechatpay.pojo.request.WeChatApplyRefundRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.WeChatMinaUnifiedOrderRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.WeChatQueryRefundRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatH5ApplyRefundRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatCloseOrderRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatPaymentNoticeRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatQueryOrder4MchRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatQueryOrder4WeChatRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatH5QueryRefundRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatRefundNoticeRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatUnifiedOrderRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatApplyRefundResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatMinaUnifiedOrderResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatQueryRefundResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatRefundNoticeResource;
import com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatRefundNoticeResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatH5ApplyRefundResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatPaymentNoticeResource;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatPaymentNoticeResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatQueryOrderResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatH5QueryRefundResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatH5RefundNoticeReqInfo;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatH5RefundNoticeResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatUnifiedOrderResponse;
import com.xbongbong.pay.pojo.PayHttpResponse;
import com.xbongbong.pay.utils.PayHttpUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

import static sun.security.x509.CertificateAlgorithmId.ALGORITHM;

/**
 * 微信支付api
 * @author 魏荣杰
 * @date 2021/1/11 17:19
 * @since
 * @version
 */
@Service("weChatPayApi")
public class WeChatPayApi {
    private static final Logger LOG = LoggerFactory.getLogger(WeChatPayApi.class);

    private static final String AUTH_TYPE = "WECHATPAY2-SHA256-RSA2048";

    @Resource
    private WeChatPayMetaContainer weChatPayMetaContainer;


    /**
     * Description: 统一下单接口
     * @param request
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatUnifiedOrderResponse
     * @author 魏荣杰
     * @date 2021/1/11 18:45
     */
    public WeChatUnifiedOrderResponse order(WeChatUnifiedOrderRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

//            String urlPath = WeChatV3UrlEnum.getUrlPath(WeChatV3UrlEnum.H5_UNIFIED_ORDER);
//            String authorization = WeChatPayHelp.buildAuthorization4V3("POST", urlPath, mchId, wechatMeta.getSerialNumber(), wechatMeta.getKeyPair().getPrivate(), JSON.toJSONString(request), AUTH_TYPE);
//            Map<String, String> headers= WeChatPayHeadUtil.getHeaders(authorization, wechatMeta.getSerialNumber());
            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.H5_UNIFIED_ORDER);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatUnifiedOrderResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }

    }

    /**
     * Description: 微信支付订单号查询
     * @param request
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatQueryOrderResponse
     * @author 魏荣杰
     * @date 2021/1/11 19:20
     */
    public WeChatQueryOrderResponse queryOrder4WeChat(WeChatQueryOrder4WeChatRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

//            String urlPath = WeChatV3UrlEnum.getUrlPath(WeChatV3UrlEnum.H5_QUERY_ORDER_WECHAT, request.getTransactionId());
//            String authorization = WeChatPayHelp.buildAuthorization4V3("GET", urlPath, mchId, wechatMeta.getSerialNumber(), privateKey, JSON.toJSONString(request), AUTH_TYPE);
//            Map<String, String> headers = WeChatPayHeadUtil.getBaseHeaders(authorization);

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.H5_QUERY_ORDER_WECHAT, request.getTransactionId());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpGetByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatQueryOrderResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 商户订单号查询
     * @param request
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatQueryOrderResponse
     * @author 魏荣杰
     * @date 2021/1/11 19:21
     */
    public WeChatQueryOrderResponse queryOrder4Mch(WeChatQueryOrder4MchRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();

            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

//            String urlPath = WeChatV3UrlEnum.getUrlPath(WeChatV3UrlEnum.HT_QUERY_ORDER_MCH, request.getOutTradeNo());
//
//            String authorization = WeChatPayHelp.buildAuthorization4V3("GET", urlPath, mchId, wechatMeta.getSerialNumber(), privateKey, JSON.toJSONString(request), AUTH_TYPE);
//
//            Map<String, String> headers = WeChatPayHeadUtil.getBaseHeaders(authorization);

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.HT_QUERY_ORDER_MCH, request.getOutTradeNo());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpGetByJson(httpClient, url, request, new HashMap<>());
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.isNull(jsonObject)) {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }
            if (jsonObject.containsKey("code")) {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), jsonObject.getString("message"));
            } else {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatQueryOrderResponse.class);
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 关闭订单
     * @param request
     * @return boolean
     * @throws
     * @author 魏荣杰
     * @date 2021/1/12 09:57
     * @since
     */
    public boolean closeOrder(WeChatCloseOrderRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

//            String urlPath = WeChatV3UrlEnum.getUrlPath(WeChatV3UrlEnum.H5_CLOSE_ORDER, request.getOutTradeNo());
//
//            String authorization = WeChatPayHelp.buildAuthorization4V3("POST", urlPath, mchId, wechatMeta.getSerialNumber(), privateKey, JSON.toJSONString(request), AUTH_TYPE);
//
//            Map<String, String> headers = WeChatPayHeadUtil.getBaseHeaders(authorization);

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.H5_CLOSE_ORDER, request.getOutTradeNo());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            if (Objects.equals(status, 200) || Objects.equals(status, 204)) {
                return true;
            } else {
                throw new PayApiException(status, payHttpResponse.getBody().getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 申请退款
     * @param request 请求体
     * @param mchId 商户id
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatApplyRefundResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/1/12 10:08
     * @since
     */
    @Deprecated
    public WeChatH5ApplyRefundResponse applyRefund(WeChatH5ApplyRefundRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();

            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());
//            request.setSignType(WeChatSignType.MD5.getType());
//            String sign4V2 = WeChatSignUtil.createSign4V2(JSON.parseObject(JSON.toJSONString(request)), v3.getAppV3Secret());
//            request.setSign(sign4V2);
//            String authorization = WeChatPayHelp.buildAuthorization4V3("POST", WeChatV3UrlEnum.H5_APPLY_REFUND.getPattern(), mchId, wechatMeta.getSerialNumber(), privateKey, JSON.toJSONString(request), AUTH_TYPE);
//
//            Map<String, String> headers = WeChatPayHeadUtil.getBaseHeaders(authorization);

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.H5_APPLY_REFUND);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByXml(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            if (!Objects.equals(status, 200)) {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }
            JSONObject jsonObject = payHttpResponse.getBody();
            WeChatH5ApplyRefundResponse response = JSON.parseObject(JSON.toJSONString(jsonObject), WeChatH5ApplyRefundResponse.class);
            if (Objects.nonNull(response)) {
                String returnCode = response.getReturnCode();
                if (Objects.nonNull(returnCode)) {
                    if (Objects.equals(returnCode, WeChatApplyRefundErrorEnum.SUCCESS.getErrorCode())) {
                        Integer couponRefundCount = response.getCouponRefundCount();
                        if (Objects.nonNull(couponRefundCount) && !Objects.equals(couponRefundCount, 0)) {
                            List<WeChatH5ApplyRefundResponse.CouponRefund> couponRefunds = new ArrayList<>();
                            for (int i = 0; i < couponRefundCount; i++) {

                                WeChatH5ApplyRefundResponse.CouponRefund couponRefund = new WeChatH5ApplyRefundResponse.CouponRefund(jsonObject.getString("coupon_type_" + i), jsonObject.getString("coupon_refund_id_" + i), jsonObject.getInteger("coupon_refund_fee_" + i));
                                couponRefunds.add(couponRefund);
                            }
                            response.setCouponRefunds(couponRefunds);
                        }
                        return response;
                    } else {
                        throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), WeChatApplyRefundErrorEnum.getByCode(returnCode) == null ? returnCode : WeChatApplyRefundErrorEnum.getByCode(returnCode).getMsg());
                    }
                } else {
                    throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
                }
            } else {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }


    /**
     * Description: 查询退款
     * @param request 请求体
     * @param mchId 商户id
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatQueryRefundResponse
     * @author 魏荣杰
     * @date 2021/1/12 13:50
     */
    @Deprecated
    public WeChatH5QueryRefundResponse queryRefund(WeChatH5QueryRefundRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();

            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());
//
//            String sign4V2 = WeChatSignUtil.createSign4V2(JSON.parseObject(JSON.toJSONString(request)), v3.getAppV3Secret());
//            request.setSign(sign4V2);
//            String authorization = WeChatPayHelp.buildAuthorization4V3("POST", WeChatV3UrlEnum.H5_QUERY_REFUND.getPattern(), mchId, wechatMeta.getSerialNumber(), privateKey, JSON.toJSONString(request), AUTH_TYPE);
//            Map<String, String> headers = WeChatPayHeadUtil.getBaseHeaders(authorization);

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.H5_QUERY_REFUND);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByXml(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            if (!Objects.equals(status, 200)) {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }

            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.isNull(jsonObject)) {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }
            WeChatH5QueryRefundResponse response = JSON.parseObject(JSON.toJSONString(request), WeChatH5QueryRefundResponse.class);
            if (Objects.nonNull(response)) {
                String returnCode = response.getReturnCode();
                if (Objects.nonNull(returnCode)) {
                    if (Objects.equals(returnCode, WeChatQueryRefundErrorEnum.SUCCESS.getErrorCode())) {
                        Integer refundCount = response.getRefundCount();
                        if (Objects.nonNull(refundCount) && !Objects.equals(refundCount, 0)) {
                            List<WeChatH5QueryRefundResponse.Refund> refunds = new ArrayList<>();
                            for (int i = 0; i < refundCount; i++) {
                                Integer couponRefundCount = jsonObject.getInteger("coupon_refund_count_" + i);


                                List<WeChatH5QueryRefundResponse.Refund.CouponRefund> couponRefunds = null;
                                if (Objects.nonNull(couponRefundCount) && !Objects.equals(couponRefundCount, 0)) {
                                    for (int j = 0; j < couponRefundCount; j++) {
                                        couponRefunds = new ArrayList<>();
                                        WeChatH5QueryRefundResponse.Refund.CouponRefund couponRefund = new WeChatH5QueryRefundResponse.Refund.CouponRefund(jsonObject.getString("coupon_refund_id_" + i + "_" + j), jsonObject.getInteger("coupon_refund_fee_" + i + "_" + j));
                                        couponRefunds.add(couponRefund);
                                    }
                                }

                                WeChatH5QueryRefundResponse.Refund refund = new WeChatH5QueryRefundResponse.Refund(jsonObject.getString("refund_channel_" + i), jsonObject.getInteger("refund_fee_" + i), jsonObject.getString("coupon_type_" + i), jsonObject.getInteger("coupon_refund_fee_" + i), jsonObject.getInteger("coupon_refund_count_" + i), jsonObject.getString("refund_status_" + i), jsonObject.getString("refund_account_" + i), jsonObject.getString("refund_recv_accout_" + i), jsonObject.getString("refund_success_time_" + i), couponRefunds);
                                refunds.add(refund);
                            }
                            response.setRefunds(refunds);
                        }
                        return response;
                    } else {
                        throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), WeChatQueryRefundErrorEnum.getByCode(returnCode) == null ? returnCode : WeChatQueryRefundErrorEnum.getByCode(returnCode).getMsg());
                    }
                } else {
                    throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
                }
            } else {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }

        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 支付通知 接收
     * @param response
     * @return com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatPaymentNoticeRequest
     * @author 魏荣杰
     * @date 2021/1/12 15:42
     */
    public WeChatPaymentNoticeRequest paymentNotice(WeChatPaymentNoticeResponse response, String apiV3Key) throws PayApiException {
        WeChatPaymentNoticeRequest weChatPaymentNoticeRequest = new WeChatPaymentNoticeRequest();
        try {
            WeChatPaymentNoticeResource weChatPaymentNoticeResource = paymentNoticeParse(response, apiV3Key);
            if (Objects.isNull(weChatPaymentNoticeResource)) {
                weChatPaymentNoticeRequest.setCode("SUCCESS");
                weChatPaymentNoticeRequest.setMessage("成功");
            } else {
                weChatPaymentNoticeRequest.setCode("FAILED");
                weChatPaymentNoticeRequest.setMessage("支付通知接收失败");
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
        return weChatPaymentNoticeRequest;
    }

    /**
     * Description: 支付通知解析
     * @param response
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatPaymentNoticeResource
     * @author 魏荣杰
     * @date 2021/1/12 14:34
     */
    public WeChatPaymentNoticeResource paymentNoticeParse(WeChatPaymentNoticeResponse response, String apiV3Key) throws PayApiException {
        try {
            WeChatPaymentNoticeResponse.Resource resource = response.getResource();
            String algorithm = resource.getAlgorithm();
            String nonce = resource.getNonce();
            String associatedData = resource.getAssociatedData();
            // 解密对象
            String ciphertext = resource.getCiphertext();
            if (Objects.equals(algorithm, "AEAD_AES_256_GCM")) {
                String decryptToString = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
                return JSON.parseObject(decryptToString, WeChatPaymentNoticeResource.class);
            } else {
                throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 退款结果通知
     * @param response
     * @return com.xbongbong.pay.platform.wechatpay.pojo.request.h5.WeChatRefundNoticeRequest
     * @author 魏荣杰
     * @date 2021/1/12 15:48
     */
    @Deprecated
    public WeChatRefundNoticeRequest refundNotice(WeChatH5RefundNoticeResponse response, String apiV3Key) throws PayApiException {
        WeChatRefundNoticeRequest weChatRefundNoticeRequest = new WeChatRefundNoticeRequest();
        try {
            WeChatH5RefundNoticeReqInfo weChatH5RefundNoticeReqInfo = refundNoticeParse(response, apiV3Key);
            if (Objects.isNull(weChatH5RefundNoticeReqInfo)) {
                weChatRefundNoticeRequest.setCode("SUCCESS");
                weChatRefundNoticeRequest.setMessage("");
            } else {
                weChatRefundNoticeRequest.setCode("FAIL");
                weChatRefundNoticeRequest.setMessage("退款结果通知失败");
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
        return weChatRefundNoticeRequest;
    }


    /**
     * Description: 退款结果通知 解析
     * @param response
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.h5.WeChatRefundNoticeResponse
     * @author 魏荣杰
     * @date 2021/1/12 14:18
     */
    @Deprecated
    private WeChatH5RefundNoticeReqInfo refundNoticeParse(WeChatH5RefundNoticeResponse response, String apiV3Key) throws PayApiException {
        try {
            String reqInfo = response.getReqInfo();

            /*
            * 1)、对加密串A做base64解码，得到加密串B；

2)、对商户key做md5，得到32位小写key* ( key设置路径：微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )

3)、用key*对加密串B做AES-256-ECB解密（PKCS7Padding）
            **/
            byte[] decode = Base64.getDecoder().decode(reqInfo);
            String keyStr = MD5Util.md5(apiV3Key).toLowerCase();
            SecretKeySpec keySpec = new SecretKeySpec(keyStr.getBytes(StandardCharsets.UTF_8), ALGORITHM);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            String decryptToString = new String(cipher.doFinal(decode), StandardCharsets.UTF_8);

            return JSON.parseObject(decryptToString, WeChatH5RefundNoticeReqInfo.class);

        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 小程序统一下单
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatMinaUnifiedOrderResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/2 09:58
     * @since
     */
    public WeChatMinaUnifiedOrderResponse minaUnifiedOrder(WeChatMinaUnifiedOrderRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());
            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.MINA_UNIFIED_ORDER);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatMinaUnifiedOrderResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 申请退款
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatApplyRefundResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/2 19:08
     * @since
     */
    public WeChatApplyRefundResponse applyRefund(WeChatApplyRefundRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());
            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.APPLY_REFUND);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatApplyRefundResponse.class);
            } else {
                throw new PayApiException(status, Objects.requireNonNull(WeChatPayErrorEnum.getCode(status)).getDescribe());
            }

        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 查询单笔退款API
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatQueryRefundResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/2 19:23
     * @since
     */
    public WeChatQueryRefundResponse queryRefund(WeChatQueryRefundRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            PrivateKey privateKey = wechatMeta.getKeyPair().getPrivate();
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(privateKey, mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());
            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.QUERY_REFUND, request.getOutRefundNo());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatQueryRefundResponse.class);
            } else {
                throw new PayApiException(status, Objects.requireNonNull(WeChatPayErrorEnum.getCode(status)).getDescribe());
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 退款结果通知
     * @param response
     * @param apiV3Key
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.WeChatRefundNoticeResource
     * @throws
     * @author 魏荣杰
     * @date 2021/2/2 19:27
     * @since
     */
    public WeChatRefundNoticeRequest refundNotice(WeChatRefundNoticeResponse response, String apiV3Key) throws PayApiException {
        WeChatRefundNoticeRequest request = new WeChatRefundNoticeRequest();
        try {
            WeChatRefundNoticeResponse.Resource resource = response.getResource();
            String nonce = resource.getNonce();
            String associatedData = resource.getAssociatedData();
            String algorithm = resource.getAlgorithm();
            String ciphertext = resource.getCiphertext();
            if (Objects.equals(algorithm, "AEAD_AES_256_GCM")) {
                String decryptToString = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
                WeChatRefundNoticeResource weChatRefundNoticeResource = JSON.parseObject(decryptToString, WeChatRefundNoticeResource.class);
                if (Objects.nonNull(weChatRefundNoticeResource)) {
                    request.setCode("SUCCESS");
                    request.setMessage("成功");
                } else {
                    request.setCode("FAILED");
                    request.setMessage("支付通知接收失败");
                }
            }
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
        return request;
    }
}
